using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace BlakeAndMattGame
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        //game screen dimensions
        int MaxX;
        int MinX = 0;
        int MaxY;
        int MinY = 0;

        int GAMESTATE = 0;

        //game objects
        GameSprite enemy;
        GameSprite player;
        Goal goal;
        Wall[] walls = new Wall[3];

        //misc stuff
        int wallIndex = 0;
        Random rand;
        MouseState currentMS;
        MouseState prevMS;
        int mouseOffset;
        Rectangle mouseArea = new Rectangle(-10, -10, 5, 5);

        //game variables
        int score = 0;
        int lives = 3;
        int collected = 0; //how many "coins" have been collected
        int targetCollect = 10; //how many "coins" need to be collected to advance

        //textures and fonts
        SpriteFont font;
        Texture2D winScreen, loseScreen, titleScreen, instructionScreen;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            this.IsMouseVisible = true;
            MaxX = graphics.GraphicsDevice.Viewport.Width;
            MinX = 0;
            MaxY = graphics.GraphicsDevice.Viewport.Height;
            MinY = 0;
            rand = new Random(CurrentTimeMillis());
            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);
            player = new GameSprite(new Vector2(10, 0), new Vector2(60, -60), Content.Load<Texture2D>("player"));
            enemy = new GameSprite(new Vector2(20, 100), new Vector2(-50, 50), Content.Load<Texture2D>("enemy"));
            goal = new Goal(new Vector2(rand.Next()%MaxX, rand.Next()%MaxY), Content.Load<Texture2D>("goal"));
            walls[0] = new Wall(new Vector2(-100, -100), Content.Load<Texture2D>("wall"), Content.Load<Texture2D>("wall2"));
            walls[1] = new Wall(new Vector2(-100, -100), Content.Load<Texture2D>("wall"), Content.Load<Texture2D>("wall2"));
            walls[2] = new Wall(new Vector2(-100, -100), Content.Load<Texture2D>("wall"), Content.Load<Texture2D>("wall2"));
            font = Content.Load<SpriteFont>("SpriteFont1");
            winScreen = Content.Load<Texture2D>("winScreen");
            loseScreen = Content.Load<Texture2D>("loseScreen");
            instructionScreen = Content.Load<Texture2D>("instructionScreen");
            titleScreen = Content.Load<Texture2D>("titleScreen");
            mouseOffset = walls[0].texture.Width / 2;
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            player.Move(graphics, gameTime);
            enemy.Move(graphics, gameTime);

            if (player.BoundingBox.Intersects(goal.BoundingBox)) //player collides with coin
            {
                collected++;
                goal.position = new Vector2(rand.Next() % MaxX, rand.Next() % MaxY);
                if (collected == targetCollect) //if player collects target amount
                {
                    GAMESTATE = 3;
                    ResetGame();
                }
            }

            if (player.BoundingBox.Intersects(enemy.BoundingBox)) //player and enemy collide
            {
                lives--;
                player.speed.X *= -1;
                player.speed.Y *= -1;
                enemy.speed.X *= -1;
                enemy.speed.Y *= -1;
                if (lives == 0)
                {
                    GAMESTATE = 4;
                    ResetGame();
                }
            }

            //when player clicks on screen
            currentMS = Mouse.GetState();
            if (currentMS.LeftButton == ButtonState.Released && prevMS.LeftButton == ButtonState.Pressed) //click
            {
                mouseArea.X = currentMS.X;
                mouseArea.Y = currentMS.Y;

                if (GAMESTATE == 0)
                    GAMESTATE = 1;
                else if (GAMESTATE == 1)
                    GAMESTATE = 2;
                else if (GAMESTATE == 2)
                {
                    bool placeWall = true;
                    foreach (Wall w in walls)
                    {
                        if (mouseArea.Intersects(w.BoundingBox))
                        {
                            w.vertical = !w.vertical;
                            placeWall = false;
                            walls[wallIndex].position = new Vector2(currentMS.X, currentMS.Y);
                        }
                    }
                    if (placeWall)
                    {
                        wallIndex++;
                        if (wallIndex >= walls.Length)
                            wallIndex = 0;
                        walls[wallIndex].vertical = false;
                        walls[wallIndex].position = new Vector2(currentMS.X - mouseOffset, currentMS.Y);
                    }
                    Console.WriteLine("WALL 1: " + walls[0].vertical);
                    Console.WriteLine("WALL 2: " + walls[1].vertical);
                    Console.WriteLine("WALL 3: " + walls[2].vertical + "\n");
                }
                else if (GAMESTATE == 3)
                    GAMESTATE = 0;
                else if (GAMESTATE == 4)
                    GAMESTATE = 0;
            }
            prevMS = currentMS;

            CheckCollision();
            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);
            spriteBatch.Begin();

            if (GAMESTATE == 0)
                spriteBatch.Draw(titleScreen, new Rectangle(0, 0, MaxX, MaxY), Color.White);
            if(GAMESTATE == 1)
                spriteBatch.Draw(instructionScreen, new Rectangle(0, 0, MaxX, MaxY), Color.White);
            if (GAMESTATE == 2)
            {
                spriteBatch.DrawString(font, "COLLECTED: " + collected + " / " + targetCollect, new Vector2(10, 30), Color.Black);
                spriteBatch.DrawString(font, "LIVES: " + lives, new Vector2(10, 10), Color.Black);
                enemy.Draw(spriteBatch);
                player.Draw(spriteBatch);
                goal.Draw(spriteBatch);
                foreach (Wall w in walls)
                    w.Draw(spriteBatch);
            }
            if(GAMESTATE == 3)
                spriteBatch.Draw(winScreen, new Rectangle(0, 0, MaxX, MaxY), Color.White);
            if(GAMESTATE == 4)
                spriteBatch.Draw(loseScreen, new Rectangle(0, 0, MaxX, MaxY), Color.White);
            spriteBatch.End();

            base.Draw(gameTime);
        }

        private void CheckCollision()
        {
            foreach (Wall w in walls)
            {
                if (player.BoundingBox.Intersects(w.BoundingBox))
                    player.speed.Y *= -1;
                if (enemy.BoundingBox.Intersects(w.BoundingBox))
                    enemy.speed.Y *= -1;

                if (player.BoundingBox.Intersects(w.LeftBoundingBox))
                    player.speed.X *= -1;
                if (player.BoundingBox.Intersects(w.RightBoundingBox))
                    player.speed.X *= -1;

                if (enemy.BoundingBox.Intersects(w.LeftBoundingBox))
                    enemy.speed.X *= -1;
                if (enemy.BoundingBox.Intersects(w.RightBoundingBox))
                    enemy.speed.X *= -1;
            }
        }

        private void ResetGame()
        {
            goal.position = new Vector2(rand.Next() % MaxX, rand.Next() % MaxY);
            lives = 3;
            collected = 0;
            foreach (Wall w in walls)
                w.position = new Vector2(-100, -100);
            player.position = new Vector2(rand.Next() % MaxX, rand.Next() % MaxY);
            enemy.position = new Vector2(rand.Next() % MaxX, rand.Next() % MaxY);
        }

        private int CurrentTimeMillis()
        {
            DateTime Jan1st1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
            return (int)((long)(DateTime.UtcNow - Jan1st1970).TotalMilliseconds / 100000000);
        }

    }
}
